﻿#include <windows.h>
#include <tchar.h>
#include <string>

// 全局变量
HINSTANCE hInst;
HWND hWndMain;
HHOOK hMouseHook;
HHOOK hKeyboardHook;
std::wstring eventLog;
// 用于限制鼠标移动事件的频率，避免日志刷屏
DWORD lastMouseMoveTime = 0;
const DWORD MOUSE_MOVE_DELAY = 500; // 500毫秒记录一次移动

// 函数声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MouseHookProc(int, WPARAM, LPARAM);
LRESULT CALLBACK KeyboardHookProc(int, WPARAM, LPARAM);
void UpdateEventLog(const std::wstring& event);
wchar_t GetCharFromKey(DWORD vkCode, bool isExtended);

// WinMain入口函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    hInst = hInstance;

    // 注册窗口类
    WNDCLASSEX wc = { 0 };
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = _T("InputMonitorClass");
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, _T("窗口注册失败！"), _T("错误"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // 创建窗口
    hWndMain = CreateWindowEx(
        0,
        _T("InputMonitorClass"),
        _T("全局输入监控器"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
        NULL, NULL, hInstance, NULL
    );

    if (hWndMain == NULL)
    {
        MessageBox(NULL, _T("窗口创建失败！"), _T("错误"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // 设置钩子
    hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hInstance, 0);
    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, hInstance, 0);

    if (hMouseHook == NULL || hKeyboardHook == NULL)
    {
        MessageBox(NULL, _T("钩子设置失败！"), _T("错误"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hWndMain, nCmdShow);
    UpdateWindow(hWndMain);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 卸载钩子
    UnhookWindowsHookEx(hMouseHook);
    UnhookWindowsHookEx(hKeyboardHook);

    return (int)msg.wParam;
}

// 窗口过程
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        // 绘制事件日志
        RECT rect;
        GetClientRect(hWnd, &rect);
        rect.top += 10;
        rect.left += 10;
        rect.right -= 10;

        DrawText(hdc, eventLog.c_str(), -1, &rect, DT_LEFT | DT_TOP);

        EndPaint(hWnd, &ps);
        break;
    }

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}

// 更新事件日志
void UpdateEventLog(const std::wstring& event)
{
    // 获取当前时间
    SYSTEMTIME st;
    GetLocalTime(&st);
    wchar_t timeStr[100];
    swprintf_s(timeStr, L"[%02d:%02d:%02d] ", st.wHour, st.wMinute, st.wSecond);

    // 添加新事件到日志
    eventLog = timeStr + event + L"\r\n" + eventLog;

    // 限制日志长度，防止内存溢出
    if (eventLog.length() > 10000)
    {
        eventLog = eventLog.substr(0, 10000);
    }

    // 刷新窗口
    InvalidateRect(hWndMain, NULL, TRUE);
    UpdateWindow(hWndMain);
}

// 鼠标钩子过程 - 监控滚轮、左右键和移动事件
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
        std::wstring event;
        bool shouldLog = true;

        // 处理鼠标滚轮事件
        if (wParam == WM_MOUSEWHEEL)
        {
            // 对于低级鼠标钩子，滚轮信息在MSLLHOOKSTRUCT的mouseData字段中
            int zDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData);
            event = (zDelta > 0) ? L"鼠标滚轮向上滚动" : L"鼠标滚轮向下滚动";

            // 添加滚轮值信息用于调试
            wchar_t deltaStr[50];
            swprintf_s(deltaStr, L" (值: %d)", zDelta);
            event += deltaStr;
        }
        // 处理鼠标左键事件
        else if (wParam == WM_LBUTTONDOWN)
        {
            event = L"鼠标左键按下";
        }
        else if (wParam == WM_LBUTTONUP)
        {
            event = L"鼠标左键释放";
        }
        // 处理鼠标右键事件
        else if (wParam == WM_RBUTTONDOWN)
        {
            event = L"鼠标右键按下";
        }
        else if (wParam == WM_RBUTTONUP)
        {
            event = L"鼠标右键释放";
        }
        // 处理鼠标移动事件
        else if (wParam == WM_MOUSEMOVE)
        {
            // 限制移动事件记录频率，避免日志刷屏
            DWORD currentTime = GetTickCount();
            if (currentTime - lastMouseMoveTime < MOUSE_MOVE_DELAY)
            {
                shouldLog = false;
            }
            else
            {
                lastMouseMoveTime = currentTime;
                event = L"鼠标移动";
            }
        }
        // 如果不是我们关注的事件，直接传递
        else
        {
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }

        // 记录事件
        if (shouldLog)
        {
            // 添加鼠标位置信息
            wchar_t posStr[100];
            swprintf_s(posStr, L" (位置: %d, %d)", pMouseStruct->pt.x, pMouseStruct->pt.y);
            event += posStr;

            UpdateEventLog(event);
        }
    }

    // 传递事件给下一个钩子
    return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

// 辅助函数：获取按键对应的字符（考虑大小写）
wchar_t GetCharFromKey(DWORD vkCode, bool isExtended)
{
    BYTE keyboardState[256] = { 0 };
    GetKeyboardState(keyboardState);

    // 对于字母键，强制设置键盘状态以获取正确的大小写
    if (vkCode >= 'A' && vkCode <= 'Z')
    {
        // 检查Shift键状态或CapsLock状态
        bool shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
        bool capsLockOn = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;

        // 根据Shift和CapsLock状态设置键盘状态
        keyboardState[vkCode] = 0x80;
        keyboardState[VK_SHIFT] = (shiftPressed ? 0x80 : 0x00);
    }

    wchar_t buffer[2] = { 0 };
    ToUnicode(vkCode, MapVirtualKey(vkCode, MAPVK_VK_TO_VSC) | (isExtended ? 0x100 : 0),
        keyboardState, buffer, 2, 0);
    return buffer[0];
}

// 键盘钩子过程 - 支持大小写区分和功能键识别
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        KBDLLHOOKSTRUCT* pKeyBoardStruct = (KBDLLHOOKSTRUCT*)lParam;
        bool isKeyDown = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
        std::wstring eventType = isKeyDown ? L"按键按下: " : L"按键释放: ";

        // 判断是否为扩展键（如F1-F12、方向键等）
        bool isExtended = (pKeyBoardStruct->flags & LLKHF_EXTENDED) != 0;
        wchar_t keyName[256] = { 0 };
        DWORD vkCode = pKeyBoardStruct->vkCode;

        // 尝试获取功能键名称
        if (GetKeyNameTextW((LONG)(pKeyBoardStruct->scanCode << 16) | (isExtended ? 0x1000000 : 0),
            keyName, 255) > 0)
        {
            // 对于字母键，补充大小写信息
            if ((vkCode >= 'A' && vkCode <= 'Z'))
            {
                // 正确的大小写判断逻辑：
                // 当CapsLock开启或Shift键按下时为大写（但不同时满足时）
                bool shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
                bool capsLockOn = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
                bool isUpperCase = shiftPressed ^ capsLockOn; // 异或运算：只有一个为真时结果为真

                std::wstring caseInfo = isUpperCase ? L" (大写)" : L" (小写)";
                UpdateEventLog(eventType + keyName + caseInfo);
            }
            else
            {
                UpdateEventLog(eventType + keyName);
            }
        }
        // 处理常规字符键
        else if (vkCode >= 0x20 && vkCode <= 0x7E)
        {
            wchar_t keyChar = GetCharFromKey(vkCode, isExtended);
            wchar_t keyStr[2] = { keyChar, L'\0' };
            UpdateEventLog(eventType + keyStr);
        }
        // 处理特殊功能键
        else
        {
            switch (vkCode)
            {
            case VK_F1: UpdateEventLog(eventType + L"F1"); break;
            case VK_F2: UpdateEventLog(eventType + L"F2"); break;
            case VK_F3: UpdateEventLog(eventType + L"F3"); break;
            case VK_F4: UpdateEventLog(eventType + L"F4"); break;
            case VK_F5: UpdateEventLog(eventType + L"F5"); break;
            case VK_F6: UpdateEventLog(eventType + L"F6"); break;
            case VK_F7: UpdateEventLog(eventType + L"F7"); break;
            case VK_F8: UpdateEventLog(eventType + L"F8"); break;
            case VK_F9: UpdateEventLog(eventType + L"F9"); break;
            case VK_F10: UpdateEventLog(eventType + L"F10"); break;
            case VK_F11: UpdateEventLog(eventType + L"F11"); break;
            case VK_F12: UpdateEventLog(eventType + L"F12"); break;
                // 可以继续添加其他特殊键的处理
            default:
                swprintf_s(keyName, L"未知键 (0x%02X)", vkCode);
                UpdateEventLog(eventType + keyName);
                break;
            }
        }
    }

    // 传递事件给下一个钩子
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
